<?php


class Rapide_Cache
{
	const ALL = 0;
	const GROUP = 1;
	const OLD = 2;
	const OLD_FROM_GROUP = 3;

	private
		$_oDriver,

		$_iLifeTime,
		$_sDriverName,
		$_bSetialize,
		$_aPreCallback,
		$_aPostCallback,
		$_sGroupName,
		$_bHashName,
		$_bHashGroupName,
		$_sCacheName;

	public function __construct($aName, array $aParams = array())
	{

		$oConfig = new Rapide_Config;
		$oConfig->load('Cache.php');

		// Default settings

		$this->_iLifeTime			= (int)$oConfig->get('Cache','lifetime');
		$this->_bSerialize		 = (bool)$oConfig->get('Cache','serialize');
		$this->_aPreCallback	 = $oConfig->get('Cache','pre_callback');
		$this->_aPostCallback	= $oConfig->get('Cache','post_callback');
		$this->_sDriverName		= $this->prepareDriverName(
														 $oConfig->get('Cache','driver'));
		$this->_bHashGroupName = $oConfig->get('Cache','hash_group');
		$this->_sGroupName		 = $this->prepareGroupName(
														 $oConfig->get('Cache','group'));
		$this->_bHashName			= $oConfig->get('Cache','hash_name');
		$this->_sCacheName		 = $oConfig->get('Cache','name');


		$sName = isset($sName) ? $sName : $this->_sCacheName;

		$this->_sCacheName = $this->prepareCacheName($this->_sCacheName);

		$this->overwriteParams($aParams);
		$this->loadDriver();
	}

	private function prepareDriverName($sName)
	{
		return 'Rapide_Cache_Driver_'.$sName;
	}

	private function overwriteParams(array $aParams)
	{
			if(array_key_exists('lifetime', $aParams))
			{
				if(!is_int($aParams['lifetime']))
				{
					throw new Rapide_Cache_Exception('Parameter "lifetime" for Cache must be integer.');
				}

				$this->_iLifeTime = $aParams['lifetime'];
			}

			if(array_key_exists('serialize', $aParams))
			{
				$this->_bSerialize = (bool)$aParams['serialize'];
			}

			if(array_key_exists('pre_callback', $aParams))
			{
				$this->_aPreCallback = $aParams['pre_callback'];
			}

			if(array_key_exists('post_callback', $aParams))
			{
				$this->_aPreCallback = $aParams['post_callback'];
			}

			if(array_key_exists('hash_name', $aParams))
			{
				$this->_bHashName = (bool)$aParams['hash_name'];
			}

			if(array_key_exists('hash_group', $aParams))
			{
				$this->_bHashGroup = (bool)$aParams['hash_group'];
			}

			if(array_key_exists('group',$aParams))
			{
				$this->_sGroupName = $this->prepareGroupName($aParams['group']);
			}

			if(array_key_exists('driver',$aParams))
			{
				 $this->_sDriverName = $this->prepareDriverName($aParams['driver']);
			}
	}

	private function loadDriver()
	{
		$oAutoloader = Rapide_Autoloader::getInstance();

		if(!$oAutoloader->load($this->_sDriverName))
		{
			throw new Rapide_Cache_Exception('Driver does not exist.');
		}

		$this->_oDriver = new $this->_sDriverName($this->_sCacheName,
																							 $this->_sGroupName,
																							 $this->_iLifeTime);
	}

	public function save($mData)
	{
		if(count($this->_aPreCallback))
		{
			$mData = call_user_func_array($this->_aPreCallback, $mData);
		}

		if($this->_bSerialize)
		{
			$mData = serialize($mData);
		}

		return $this->_oDriver->save($mData);
	}

	public function load()
	{
		$mData = $this->_oDriver->load();

		if($mData)
		{
			if($this->_bSerialize)
			{
				$mData = unserialize($mData);
			}

			if(count($this->_aPostCallback))
			{
				$mData = call_user_func_array($this->_aPostCallback, $mData);
			}

			return $mData;
		}
		else
		{
			return false;
		} 
	}


	public function clear($iType,array $aParams = array())
	{
		switch($iType)
		{
			case self::ALL:
				$this->_oDriver->clearAll();
				break;

			case self::GROUP:
				$this->_oDriver->clearGroup($this->prepareGroupName($aParams['group']));
				break;

			case self::OLD:
				$this->_oDriver->clearOld();
				break;

			case self::OLD_FROM_GROUP:
				$this->_oDriver->clearOldFromGroup($this->prepareGroupName($aParams['group']));
				break;

			default:
				$this->_oDriver->clearAllCache();
		}

	}

	public function remove()
	{
		$this->_oDriver->remove();
	}

	public function start()
	{
		 ob_start();
	}

	public function stop()
	{
		$this->save(ob_get_clean());
	}

	private function prepareCacheName($sCacheName)
	{
		if($this->_bHashName)
			$sCacheName = $this->hash($sCacheName);

		return $sCacheName;
	}

	private function prepareGroupName($sGroupName)
	{
		if(!is_null($sGroupName))
		{
			if($this->_bHashGroupName)
			{
				return($this->hash($sGroupName));
			}
		}

		return $sGroupName;
	}

	private function hash($sEntry)
	{
		return md5(base64_encode($sEntry));
	}
}

?>